package org.example.gxpt.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.example.gxpt.common.constant.*;
import org.example.gxpt.common.context.LoginContext;
import org.example.gxpt.common.context.SecurityContext;
import org.example.gxpt.common.exception.AccountLockedException;
import org.example.gxpt.common.exception.AccountNotFoundException;
import org.example.gxpt.common.exception.PasswordErrorException;
import org.example.gxpt.common.properties.JwtProperties;
import org.example.gxpt.common.properties.RedisProperties;
import org.example.gxpt.common.result.PageResult;
import org.example.gxpt.common.result.Result;
import org.example.gxpt.common.utils.JwtUtil;
import org.example.gxpt.mapper.ShowroomAdminMapper;
import org.example.gxpt.mapper.SystemAdminMapper;
import org.example.gxpt.mapper.UserRoleMapper;
import org.example.gxpt.pojo.dto.LoginDTO;
import org.example.gxpt.pojo.dto.SystemAdminDTO;
import org.example.gxpt.pojo.dto.SystemAdminPageQueryDTO;
import org.example.gxpt.pojo.dto.SystemAdminUpdateDTO;
import org.example.gxpt.pojo.entity.SystemAdmin;
import org.example.gxpt.pojo.entity.User;
import org.example.gxpt.pojo.entity.UserRole;
import org.example.gxpt.pojo.userdetails.LoginUser;
import org.example.gxpt.pojo.vo.SystemAdminLoginVO;
import org.example.gxpt.service.SystemAdminService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SystemAdminServiceImpl implements SystemAdminService {

    @Autowired
    private SystemAdminMapper systemAdminMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private UserRoleMapper userRoleMapper;

    /**
     * 系统管理员注册
     *
     * @param systemAdminDTO
     */
    @Override
    @Transactional
    public void save(SystemAdminDTO systemAdminDTO) {

        SystemAdmin systemAdmin = new SystemAdmin();
        BeanUtils.copyProperties(systemAdminDTO, systemAdmin);
        //systemAdmin.setPassword(DigestUtils.md5DigestAsHex(systemAdminDTO.getPassword().getBytes()));
        systemAdmin.setPassword(passwordEncoder.encode(systemAdminDTO.getPassword()));
//        log.info(systemAdmin.toString());
        systemAdminMapper.insert(systemAdmin);
        UserRole userRole = new UserRole();
        userRole.setUsername(systemAdmin.getUsername());
        userRole.setPhone(systemAdmin.getPhone());
        userRole.setRole(RoleConstant.SYSTEM_ADMIN);
        userRole.setRoleId(systemAdmin.getId());
        userRoleMapper.insert(userRole);
    }

    /**
     * 系统管理员登陆
     *
     * @param loginDTO
     * @return
     */
    @Override
    public SystemAdminLoginVO login(LoginDTO loginDTO) {

        LoginContext.setCurrentRole(LoginRoleConstant.SYSTEM_ADMIN);

        //AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }

        //如果认证通过，使用生成一个jwt，存入loginVO中返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        SystemAdmin systemAdmin = loginUser.getSystemAdmin();

        //生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.ROLE, RoleConstant.SYSTEM_ADMIN);
        claims.put(JwtClaimsConstant.ID, systemAdmin.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getSecretKey(),
                jwtProperties.getTtl(),
                claims);

        SystemAdminLoginVO systemAdminLoginVO = SystemAdminLoginVO.builder()
                .id(systemAdmin.getId())
                .username(systemAdmin.getUsername())
                .token(token)
                .name(systemAdmin.getName())
                .avatar(systemAdmin.getAvatar())
                .build();

        //存入redis
        redisTemplate.opsForValue().set(RedisConstant.LOGIN_SYSTEM_ADMIN + systemAdmin.getId().toString(),
                loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);
        return systemAdminLoginVO;
    }


    /**
     * 系统管理员分页查询
     *
     * @param systemAdminPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuery(SystemAdminPageQueryDTO systemAdminPageQueryDTO) {

        PageHelper.startPage(systemAdminPageQueryDTO.getPage(), systemAdminPageQueryDTO.getPageSize());

        Page<SystemAdmin> page = systemAdminMapper.pageQuery(systemAdminPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 系统管理员登出
     *
     * @return
     */
    @Override
    public Result logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long id = loginUser.getSystemAdmin().getId();
        //在Redis中删除用户信息
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SYSTEM_ADMIN + id);
        return Result.success();
    }

    /**
     * 根据id更新系统管理员
     *
     * @param systemAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateById(SystemAdminUpdateDTO systemAdminUpdateDTO) {

        SystemAdmin systemAdmin = new SystemAdmin();
        BeanUtils.copyProperties(systemAdminUpdateDTO, systemAdmin);
        systemAdmin.setPassword(passwordEncoder.encode(systemAdminUpdateDTO.getPassword()));
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SYSTEM_ADMIN + systemAdmin.getId());
        systemAdminMapper.update(systemAdmin);
        UserRole userRole = UserRole.builder()
                .role(RoleConstant.SYSTEM_ADMIN)
                .roleId(systemAdmin.getId())
                .phone(systemAdmin.getPhone())
                .username(systemAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);

    }

    /**
     * 根据上下文更新系统管理员数据
     *
     * @param systemAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateByContext(SystemAdminUpdateDTO systemAdminUpdateDTO) {

        Long id = null;
        try {
            id = SecurityContext.getCurrentLoginUser().getSystemAdmin().getId();
        } catch (Exception e) {
            throw new RuntimeException("用户未登录");
        }
        SystemAdmin systemAdmin = new SystemAdmin();
        BeanUtils.copyProperties(systemAdminUpdateDTO, systemAdmin);
        systemAdmin.setId(id);
        systemAdmin.setPassword(passwordEncoder.encode(systemAdminUpdateDTO.getPassword()));
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SYSTEM_ADMIN + systemAdmin.getId());
        systemAdminMapper.update(systemAdmin);
        UserRole userRole = UserRole.builder()
                .role(RoleConstant.SYSTEM_ADMIN)
                .roleId(systemAdmin.getId())
                .phone(systemAdmin.getPhone())
                .username(systemAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);
    }

    /**
     * 根据id更新系统管理员状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateStatus(Long id, Integer status) {

        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SYSTEM_ADMIN + id);
        systemAdminMapper.updateStatus(id, status);
    }

    /**
     * 根据id删除系统管理员
     *
     * @param id
     */
    @Override
    @Transactional
    public void deleteById(Long id) {
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_SYSTEM_ADMIN + id);
        userRoleMapper.delete(UserRole.builder().roleId(id).role(RoleConstant.SYSTEM_ADMIN).build());
        systemAdminMapper.deleteById(id);
    }

    /**
     * 根据id查询系统管理员
     *
     * @param id
     * @return
     */
    @Override
    public SystemAdmin getById(Long id) {
        return systemAdminMapper.getById(id);
    }

    /**
     * 全部系统管理员数据
     *
     * @return
     */
    @Override
    public List<SystemAdmin> listAll() {
        return systemAdminMapper.listAll();
    }


}
